Thinking in java 附录一之多态之向上转型向下转型

多态

将一条消息发给对象时,如果并不知道对方的具体类型是什么,但采取的行动同样是正确的,这种情况就叫 作“多形性”(Polymorphism).


多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作.

向上转型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class Player {
public void play(){
System.out.println("player plays game");
}

public void recharge(){
System.out.println("player recharges");
}
}


public class DotaPlayer extends Player{
public void play(){
System.out.println("dota players play dota");
}

public void complain(){
System.out.println("dota players complain");
}
}


public class LOLPlayer extends Player{
public void play(){
System.out.println("LOL player plays LOL");
}

public void recharge(){
System.out.println("LOL player is rich,likes to recharge");
}
}


public class Test {
public static void main(String[] args) {
Player player = new Player();
Player dotaPlayer = new DotaPlayer();
Player LOLPlayer = new LOLPlayer();

player.play();
player.recharge();
dotaPlayer.play();
dotaPlayer.recharge();
LOLPlayer.play();
LOLPlayer.recharge();
}
}

结果为:
// plays game
//player recharges
//dota players play dota
//player recharges
//LOL player plays LOL
//LOL player is rich,likes to recharge

向上转型后,父类与子类中都有同样的方法时,父类被子类方法覆盖。父类中有的而子类中没有的方法保持原样。

向下转型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Test {
public static void main(String[] args) {
Player player = new Player();
Player dotaPlayer = new DotaPlayer();
Player LOLPlayer = new LOLPlayer();

DotaPlayer dotaPlayer2 = (DotaPlayer) dotaPlayer;
LOLPlayer LOLPlayer2 = (LOLPlayer) LOLPlayer;
dotaPlayer2.play();
dotaPlayer2.recharge();
LOLPlayer2.play();
LOLPlayer2.recharge();

//此代码会抛出运行时期异常
//LOLPlayer player2 = (LOLPlayer) new Player();
}
}

结果:
//dota players play dota
//player recharges
//LOL player plays LOL
//LOL player is rich,likes to recharge
  • 向下转型父类对象指向的是子类对象.
  • 向下转型只能转型为本类对象.
向下转型实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Test {
public static void main(String[] args) {
Player player = new Player();
Player dotaPlayer = new DotaPlayer();
Player LOLPlayer = new LOLPlayer();

play(player);
play(dotaPlayer);
play(LOLPlayer);
}

public static void play(Player player){
if(player instanceof DotaPlayer){
DotaPlayer dotaPlayer = (DotaPlayer)player;
dotaPlayer.play();
dotaPlayer.complain();
}else if(player instanceof LOLPlayer){
LOLPlayer lolPlayer = (LOLPlayer)player;
lolPlayer.play();
lolPlayer.recharge();
}else{
player.play();
}
}
}
结果:
//player plays game
//dota players play dota
//dota players complain
//LOL player plays LOL
//LOL player is rich,likes to recharge

通过判断他是什么玩家来判断他打完游戏的动作,普通玩家打完游戏就没了,dota玩家打完就抱怨,而lol玩家,打完游戏就充钱. 老马:我都亏的坐不起公交车了.jpg

多态进阶篇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class A {
public String show(D obj) {
return ("A and D");
}

public String show(A obj) {
return ("A and A");
}
}

class B extends A{
public String show(B obj){
return ("B and B");
}

public String show(A obj){
return ("B and A");
}
}

class C extends B{
}

class D extends B{
}

public class Demo {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();

System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
结果:
//1--A and A
//2--A and A
//3--A and D
//4--B and A
//5--B and A
//6--A and D
//7--B and B
//8--B and B
//9--A and D
引出多态进阶规则
  • 当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,引用变量类型决定可调用的方法。如果子类中没有覆盖该方法,那么会去父类中寻找。

  • 继承链中对象方法的调用的优先级:
    this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

对例子的分析

前三个例子较为简单,从第四个开始分析。

  • a2.show(b)

    将四个show方法编号,由于a2为B对象向上转型,所以相同的方法会被重载,子类的方法父类无法使用,方法2和3被排除,所以此时为this.show((super)O),答案为B and A

  • a2.show(c)

    同样的a2为B对象向上转型,所以方法3排除,方法2会被4覆盖,所以依旧为this.show((super)O),答案为B and A

  • a2.show(d)

    同前两者一样,方法2和方法3被排除,此时调用super.show(O),答案为A and D

  • b.show(b)

    B继承于A,方法2无效,此时调用this.show(O),答案为B and B

  • b.show(c)

    首先由于B继承于A,方法2无效,又由于参数中没有(C obj),所以只能调用this.show((super)O),答案为B and B

  • b.show(d)

    排除方法2,此时A中存在show(O),所以此时为调用super.show(O),答案为A and D

附:
我的GitHub同性交友首页tanmibo.github.io